﻿using System;
using System.Threading;
using Fadd.Logging;
using Fadd.Messaging;

namespace Fadd.IO.Consoles
{
    /// <summary>
    /// Hooks the regular console window.
    /// </summary>
    
	public class StandardConsole : IConsole, IStartable
	{
		private readonly IMessageBroker _messageBroker;
		private readonly ILogger _logger = LogManager.GetLogger<StandardConsole>();
		private readonly Thread _myThread;

		/// <summary>
		/// Initializes a new instance of the <see cref="StandardConsole"/> class.
		/// </summary>
        public StandardConsole(IMessageBroker messageBroker)
		{
			_messageBroker = messageBroker;
			_myThread = new Thread(ConsoleThread) { IsBackground = true };
		}

		/// <summary>
		/// Reads input from console and invokes the <see cref="Command"/> message.
		/// </summary>
		private void ConsoleThread()
		{
			while (true)
			{
				try
				{
					string line = Console.ReadLine();
					if (line == null)
						continue;

					Console.WriteLine(line);
					string[] args;
					string name = ParseCommandLine(line, out args);

					_messageBroker.Publish(new Command(name, args));
				}
				catch (Exception err)
				{
					if (err is ThreadAbortException)
						return;

					_logger.Warning("Failed to read from console", err);
				}
			}
		}

		internal string ParseCommandLine(string line, out string[] args)
		{
			string name;
			int pos = line.IndexOf(' ');
			if (pos == -1)
			{
				name = line;
				args = new string[0];
			}
			else
			{
				name = line.Substring(0, pos);
				args = line.Remove(0, pos + 1).Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
			}
			return name;
		}

		#region IConsole Members

		/// <summary>
		/// Gets name of console
		/// </summary>
		/// <example>
		/// Windows
		/// </example>
		public string Name
		{
			get { return "Windows"; }
		}

		#endregion

		/// <summary>
		/// Start component
		/// </summary>
		public void Start()
		{
			_myThread.Start();
		}

		/// <summary>
		/// Stop component
		/// </summary>
		public void Stop()
		{
		}

		/// <summary>
		/// Consume a message from the <see cref="IMessageBroker"/>
		/// </summary>
		/// <param name="message">Message to consume</param>
		public void Consume(ConsoleOutput message)
		{
			ConsoleColor color = Console.ForegroundColor;
			Console.ForegroundColor = message.Color;
			Console.WriteLine(message.Text);
			Console.ForegroundColor = color;
		}

		public void WriteLine(ConsoleColor color, string value)
		{
			ConsoleColor orgColor = Console.ForegroundColor;
			Console.ForegroundColor = color;
			Console.WriteLine(value);
			Console.ForegroundColor = orgColor;
		}

		public void WriteLine(string value)
		{
			Console.WriteLine(value);
		}
	}
}
